/**
 * 线程安全栈:
 * 线程在等待锁时，就会无所事事。
 * 线程浪费宝贵的资源去检查数据
 */
#include <exception>
#include <iostream>
#include <thread>
#include <mutex>
#include <stack>

// 空栈的函数对象
struct empty_stack: std::exception {
    const char* what() const throw();
};

template<typename T>
class threadSafe_stack {
public:
    threadSafe_stack() { }
    threadSafe_stack(const threadSafe_stack& other) {
        std::lock_guard<std::mutex> lock(other.m);
        data = other.data;
    }
    threadSafe_stack& operator=(const threadSafe_stack&) = delete;

    void push(T new_val) {
        std::lock_guard<std::mutex> lock(m);
        data.push(std::move(new_val));
    }

    // 弹出一个对象
    std::shared_ptr<T> pop() {
        std::lock_guard<std::mutex> lock(m);
        if (data.empty()) {
            throw empty_stack(); // 上述函数对象
        }
        // 封装share_ptr给res
        std::shared_ptr<T> const res(std::make_shared<T>(std::move(data.pop())));
        data.pop();
        return res;
    }

    // 弹出value，通过move
    void pop(T& value) {
        std::lock_guard<std::lock> lock(m);
        if (data.empty()) {
            throw empty_stack();
        }
        value = std::move(data.top());
        data.pop();
    }

    bool empty() const {
        std::lock_guard<std::mutex> lock(m);
        return data.empty();
    }

private:
    std::stack<T> data;
    mutable std::mutex m;
};